<template>
  <div class="app-container">
    <el-card shadow="never">
      <el-row :gutter="20">
        <el-col :span="6">
          <el-affix target=".app-container" :offset="100">
            <el-card class="box-card nodelist">
              <template #header>
                <div class="card-header" align="center">
                  <span>{{ $t("location.unlBindDevices") }}</span>
                </div>
              </template>

              <el-scrollbar max-height="400px" :always="true">
                <div
                  v-for="item in dragItems"
                  v-if="dragItems.length > 0"
                  :key="item.deviceId"
                  class="draggable-item"
                  draggable="true"
                  @dragstart="(event) => onDragStart(item, event)"
                >
                  <el-text>{{ item.deviceRemark }}</el-text>
                </div>

                <div v-else>
                  <el-empty :description="$t('location.noidleDevices')" />
                </div>
              </el-scrollbar>
            </el-card>
          </el-affix>
        </el-col>
        <el-col :span="18">
          <div class="mb-10px">
            <el-button
              v-hasPerm="['location:add']"
              type="success"
              icon="plus"
              @click="handleOpenDialog(0)"
            >
              {{ $t("common.add") }}
            </el-button>
          </div>
          <div v-if="regionName">
            {{ t("customer.region.name") }}:
            <el-text class="mx-1" type="primary">{{ regionName }}</el-text>
          </div>
          <el-table
            v-loading="loading"
            stripe
            :data="tableData"
            highlight-current-row
            row-key="localId"
            :expand-row-keys="['1']"
            default-expand-all
            :tree-props="{
              children: 'children',
              hasChildren: 'hasChildren',
            }"
          >
            <el-table-column fixed :label="$t('location.name')" width="150">
              <template #default="scope">
                {{ scope.row.name }}
              </template>
            </el-table-column>

            <el-table-column
              sortable
              :label="$t('location.bindDevices')"
              align="left"
              prop="devices"
              width="300"
              max-width="400"
            >
              <template #default="{ row }">
                <div
                  class="droppable-cell"
                  :class="{ highlight: row.isDragOver }"
                  @dragover.prevent="onDragOver"
                  @dragenter="onDragEnter(row)"
                  @dragleave="onDragLeave(row)"
                  @drop="onDrop(row, $event)"
                >
                  <div>
                    <el-tag
                      v-for="(item, index) in row.droppedData"
                      :key="index"
                      closable
                      class="dropped-tag"
                      @close="removeItem(row, index)"
                    >
                      {{ item.deviceRemark ? item.deviceRemark : item.deviceSnId }}
                    </el-tag>
                  </div>
                </div>
              </template>
            </el-table-column>
            <el-table-column sortable :label="$t('location.isForbid')" align="left" prop="isForbid">
              <template #default="scope">
                <el-switch
                  v-model="scope.row.isForbid"
                  :active-value="1"
                  :inactive-value="0"
                  @change="handleSwitchChange(scope.row.localId, scope.row.isForbid, scope.row)"
                />
              </template>
            </el-table-column>
            <el-table-column :label="$t('common.remark')" align="left" prop="remark" />
            <!--<el-table-column :label="$t('common.sort')" align="center" prop="sort" />-->
            <el-table-column fixed="right" align="center" :label="$t('common.action')" width="200">
              <template #default="scope">
                <!--<el-button
                  v-hasPerm="['location:add']"
                  type="primary"
                  link
                  size="small"
                  icon="plus"
                  @click.stop="handleOpenBindDialog(scope.row.localId)"
                >
                  {{ t("location.bindDevices") }}
                </el-button>-->

                <el-button
                  v-hasPerm="['location:add']"
                  type="primary"
                  link
                  size="small"
                  icon="plus"
                  @click.stop="handleOpenDialog(scope.row.localId)"
                >
                  {{ $t("common.add") }}
                </el-button>
                <el-button
                  v-hasPerm="['location:edit']"
                  type="primary"
                  link
                  size="small"
                  icon="edit"
                  @click.stop="handleOpenDialog(undefined, scope.row.localId)"
                >
                  {{ $t("common.edit") }}
                </el-button>
                <el-button
                  v-hasPerm="['location:delete']"
                  type="danger"
                  link
                  size="small"
                  icon="delete"
                  @click.stop="handleDelete(scope.row.localId)"
                >
                  {{ $t("common.delete") }}
                </el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-col>
      </el-row>
    </el-card>

    <el-drawer v-model="dialog.visible" :title="dialog.title" size="50%" @close="handleCloseDialog">
      <el-form ref="formRef" :model="formData" :rules="rules">
        <el-form-item :label="$t('location.level1')" prop="parentId">
          <el-tree-select
            v-model="formData.parentId"
            :placeholder="$t('location.chooseParentLevel')"
            :data="options"
            filterable
            check-strictly
            :render-after-expand="false"
          />
        </el-form-item>

        <el-form-item :label="$t('location.name')" prop="name">
          <el-input
            v-model="formData.name"
            :placeholder="$t('common.plsInput') + $t('location.name')"
          />
        </el-form-item>
        <el-form-item :label="$t('common.remark')" prop="remark">
          <el-input v-model="formData.remark" />
        </el-form-item>
        <!--<el-form-item :label="$t('common.sort')" prop="sort">
          <el-input-number
            v-model="formData.sort"
            style="width: 100px"
            controls-position="right"
            :min="0"
          />
        </el-form-item>-->
      </el-form>

      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleSubmit">{{ $t("common.confirm") }}</el-button>
          <el-button @click="handleCloseDialog">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-drawer>

    <!--<el-drawer
      v-model="bindDeviceDialog.visible"
      :title="bindDeviceDialog.title"
      size="50%"
      @close="handleBindDeviceCloseDialog"
    >
      <el-transfer
        v-model="rightValues"
        class="custom-transfer"
        :titles="[t('location.unlBindDevices'), t('location.hasBindDevices')]"
        :data="leftData"
        @change=""
      />
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="handleTransferChange">
            {{ $t("common.confirm") }}
          </el-button>
          <el-button @click="handleBindDeviceCloseDialog">{{ $t("common.cancel") }}</el-button>
        </div>
      </template>
    </el-drawer>-->
  </div>
</template>
<script setup lang="ts">
import { useI18n } from "vue-i18n";
const { t } = useI18n();
defineOptions({
  name: "Location",
  inheritAttrs: false,
});
interface XOption {
  key: number;
  label: string;
}

const leftData = ref<XOption[]>();
const rightValues = ref<number[]>();
const allRightValue = ref<number[]>();
import LocationAPI, { LocationForm, LocationVO } from "@/api/location/index";
import DeviceAPI from "@/api/device/index";

const formRef = ref(ElForm);
const selectedLocalId = ref(0);
const loading = ref(false);
const dialog = reactive({
  title: t("common.add"),
  visible: false,
});
const regionName = ref<any>("");

if (localStorage.getItem("regionName") != null) {
  regionName.value = localStorage.getItem("regionName");
}

const bindDeviceDialog = reactive({
  title: t("location.bindDevices"),
  visible: false,
});

const tableData = reactive<LocationVO[]>([]);
const options = ref<OptionType[]>([]);
const initialFormData = ref<LocationForm>({
  localId: undefined,
  name: "",
  remark: "",
  parentId: 0,
  isForbid: 0,
  sort: 0,
});

const formData = ref({ ...initialFormData.value });

const rules = reactive({
  parentId: [
    { required: true, message: t("common.plsChoose") + t("location.level1"), trigger: "blur" },
  ],
  name: [{ required: true, message: t("common.plsInput") + t("location.name"), trigger: "blur" }],
});

function handleQuery() {
  loading.value = true;
  LocationAPI.getList()
    .then((data) => {
      Object.assign(tableData, data);
      /*tableData.value = data.map((row: any) => ({
        localId: row.localId,
        name: row.name,
        remark: row.remark,
        parentId: row.parentId,
        isForbid: row.isForbid,
        sort: row.sort,
        hasChildren: row.hasChildren,
        children: row.children,
        droppedData: row.devices || [],
        isDragOver: false,
      }));
      console.log(tableData.value);*/
    })
    .finally(() => {
      loading.value = false;
    });
}

function handleOpenDialog(parentId?: number, localId?: number) {
  if (!localId) {
    formData.value = {
      localId: undefined,
      parentId: 0,
      sort: 0,
      name: "",
      isForbid: 0,
      remark: "",
    };
  }
  loading.value = true;
  LocationAPI.getOptions(true)
    .then((data) => {
      options.value = [{ value: 0, label: t("location.level1"), children: data }];
    })
    .then(() => {
      dialog.visible = true;
      if (localId) {
        dialog.title = t("common.edit");
        LocationAPI.getFormData(localId).then((data) => {
          initialFormData.value = { ...data };
          formData.value = data;
        });
      } else {
        dialog.title = t("common.add");
        formData.value.parentId = parentId;
      }
    })
    .catch((err) => {
      console.error(err);
    })
    .finally(() => {
      loading.value = false;
    });
}

function handleOpenBindDialog(localId: number) {
  selectedLocalId.value = localId;
  DeviceAPI.getIdleDevce()
    .then((res) => {
      const _leftData: XOption[] = [];
      if (res.length > 0) {
        for (let i = 0; i < res.length; i++) {
          let typeName: string = "";
          if (res[i].deviceType == "gateway") {
            typeName = t("device.deviceType.gateway");
          } else if (res[i].deviceType == "node") {
            typeName = t("device.deviceType.node");
          } else {
            typeName = t("common.unknown");
          }
          _leftData.push({
            key: res[i].deviceId,
            label: res[i].deviceSnId + " " + (res[i].deviceRemark ?? typeName),
          });
        }

        leftData.value = _leftData;
      }
      DeviceAPI.getLocationBindDevices(localId)
        .then((res) => {
          if (res.length > 0) {
            const _rightData: number[] = [];
            for (let i = 0; i < res.length; i++) {
              let typeName: string = "";
              if (res[i].deviceType == "gateway") {
                typeName = t("device.deviceType.gateway");
              } else if (res[i].deviceType == "node") {
                typeName = t("device.deviceType.node");
              } else {
                typeName = t("common.unknown");
              }
              _leftData.push({
                key: res[i].deviceId,
                label: res[i].deviceSnId + " " + (res[i].deviceRemark ?? typeName),
              });
              _rightData.push(res[i].deviceId);
            }
            rightValues.value = _rightData;
            leftData.value = _leftData;
          }
        })
        .catch((err) => {
          console.error(err);
        });
    })
    .catch((err) => {
      console.error(err);
    })
    .finally(() => {
      loading.value = false;
    });
  bindDeviceDialog.visible = true;
  bindDeviceDialog.title = t("location.bindDevices");
}

/**
 * submit form
 */
function handleSubmit() {
  formRef.value.validate((isValid: boolean) => {
    if (isValid) {
      const localId = formData.value.localId;
      if (localId) {
        LocationAPI.update(localId, formData.value).then((res) => {
          if (res.data.code == 200) {
            ElMessage.success(res.data.message);
            handleCloseDialog();
            handleQuery();
          } else {
            ElMessage.error(res.data.message);
          }
        });
      } else {
        LocationAPI.add(formData.value).then((res) => {
          if (res.data.code != 200) {
            ElMessage.error(res.data.message);
          } else {
            ElMessage.success(res.data.message);
            handleCloseDialog();
            handleQuery();
          }
        });
      }
    }
  });
}

function handleDelete(localId: number) {
  if (!localId) {
    ElMessage.warning(t("common.plsChooseDeleteItem"));
    return false;
  }

  ElMessageBox.confirm(t("common.confirmDelete"), t("common.warning"), {
    confirmButtonText: t("common.confirm"),
    cancelButtonText: t("common.cancel"),
    type: "warning",
  }).then(
    () => {
      loading.value = true;
      LocationAPI.deleteById(localId)
        .then((res) => {
          if (res.data.code == 200) {
            ElMessage.success(res.data.message);
            handleQuery();
          } else {
            ElMessage.error(res.data.message);
          }
        })
        .finally(() => {
          loading.value = false;
        });
    },
    () => {
      ElMessage.info(t("common.cancelDelete"));
    }
  );
}

function resetRorm() {
  formRef.value.resetFields();
  formRef.value.clearValidate();
  formData.value = { ...initialFormData.value };
}

function handleCloseDialog() {
  dialog.visible = false;
  resetRorm();
}

function handleBindDeviceCloseDialog() {
  bindDeviceDialog.visible = false;
}

function handleTransferChange() {
  const postData: any[] = [];
  if (allRightValue.value != undefined && allRightValue.value.length > 0) {
    allRightValue.value.forEach((element) => {
      postData.push({
        localId: selectedLocalId.value,
        deviceId: element,
      });
    });
  }
  LocationAPI.setDevices(selectedLocalId.value, postData)
    .then((res) => {
      if (res.data.code == 200) {
        ElMessage.success(res.data.message);
        handleBindDeviceCloseDialog();
        handleQuery();
      } else {
        ElMessage.error(res.data.message);
      }
    })
    .catch((err) => {
      console.error(err);
    });
}

function udpateForbid(localId: number, isForbid: number) {
  LocationAPI.updateForbidStatus(localId, isForbid).then((res) => {
    if (res.data.code == 200) {
      ElMessage.success(res.data.message);
    } else {
      ElMessage.error(res.data.message);
    }
  });
}

function handleSwitchChange(localId: number, isForbid: number, row: any) {
  //need to check parent id is forbid
  if (isForbid == 0) {
    LocationAPI.getParentIsForbid(localId).then((res) => {
      if (res.isForbid > 0) {
        row.isForbid = 1;
        ElMessage.error(t("location.parentForbid"));
        return;
      }
      updateIsForbidRecursively(tableData, localId, isForbid);
    });
  } else {
    updateIsForbidRecursively(tableData, localId, isForbid);
  }
}

function updateIsForbidRecursively(nodes: LocationVO[], localId: number, isForbid: number): void {
  for (let i = 0; i < nodes.length; i++) {
    if (nodes[i].localId === localId) {
      nodes[i].isForbid = isForbid;
      udpateForbid(localId, isForbid);
      updateChildren(nodes[i].children, isForbid);
      return;
    }
    if (nodes[i].children) {
      updateIsForbidRecursively(nodes[i].children || [], localId, isForbid);
    }
  }
}

function updateChildren(nodes: LocationVO[] | undefined, isForbid: number): void {
  if (!nodes) return;
  for (let node of nodes) {
    node.isForbid = isForbid;
    if (node.localId != undefined) {
      udpateForbid(node.localId, isForbid);
    }
    if (node.children) {
      updateChildren(node.children, isForbid);
    }
  }
}

watch(
  () => rightValues,
  (newTargetData, oldTargetData) => {
    allRightValue.value = newTargetData.value;
  },
  { deep: true }
);

const dragItems = ref<DragItem[]>([]);

interface DragItem {
  deviceId: number;
  deviceRemark: string;
}

function getIdleDevces() {
  const _leftData: DragItem[] = [];
  DeviceAPI.getIdleDevce()
    .then((res) => {
      if (res.length > 0) {
        for (let i = 0; i < res.length; i++) {
          let typeName: string = "";
          if (res[i].deviceType == "gateway") {
            typeName = t("device.deviceType.gateway");
          } else if (res[i].deviceType == "node") {
            typeName = t("device.deviceType.node");
          } else {
            typeName = t("common.unknown");
          }
          _leftData.push({
            deviceId: res[i].deviceId,
            deviceRemark: res[i].deviceRemark ?? res[i].deviceSnId,
          });
        }
      }
      dragItems.value = _leftData;
    })
    .catch((err) => {
      console.error(err);
    });
}

const onDragStart = (item: { deviceId: number; deviceRemark: string }, event: DragEvent) => {
  event.dataTransfer?.setData("text/plain", JSON.stringify(item));
};

const onDragOver = (event: DragEvent) => {
  event.preventDefault();
};

const onDragEnter = (row: any) => {
  row.isDragOver = true;
};

const onDragLeave = (row: any) => {
  row.isDragOver = false;
};

const onDrop = (row: any, event: DragEvent) => {
  event.preventDefault();
  row.isDragOver = false;
  const data = event.dataTransfer?.getData("text/plain");
  if (data) {
    const droppedItem = JSON.parse(data);
    if (row.droppedData == undefined) {
      row.droppedData = [];
    }
    if (!row.droppedData.find((item: any) => item.deviceId === droppedItem.deviceId)) {
      row.droppedData.push(droppedItem);
    }
    console.log(row.droppedData);
    const postData: any[] = [];
    if (row.droppedData != undefined && row.droppedData.length > 0) {
      for (let i = 0; i < row.droppedData.length; i++) {
        postData.push({
          localId: row.localId,
          deviceId: row.droppedData[i].deviceId,
        });
      }
    }

    LocationAPI.setDevices(row.localId, postData)
      .then((res) => {
        if (res.data.code == 200) {
          ElMessage.success(res.data.message);
          getIdleDevces();
        } else {
          ElMessage.error(res.data.message);
        }
      })
      .catch((err) => {
        console.error(err);
      });
  }
};

const removeItem = (row: any, index: number) => {
  row.droppedData.splice(index, 1);
  const postData: any[] = [];
  if (row.droppedData != undefined && row.droppedData.length > 0) {
    for (let i = 0; i < row.droppedData.length; i++) {
      postData.push({
        localId: row.localId,
        deviceId: row.droppedData[i].deviceId,
      });
    }
  }

  LocationAPI.setDevices(row.localId, postData)
    .then((res) => {
      if (res.data.code == 200) {
        ElMessage.success(res.data.message);
        getIdleDevces();
      } else {
        ElMessage.error(res.data.message);
      }
    })
    .catch((err) => {
      console.error(err);
    });
};

onMounted(() => {
  getIdleDevces();
  handleQuery();
});
</script>
<style scoped>
.custom-transfer {
  width: 1200px;
}

.custom-transfer .el-transfer-panel__body {
  width: 600px;
}

.draggable-item {
  padding: 3px;
  margin: 10px 0;
  cursor: grab;
  background-color: #f5f5f5;
  border: 1px solid #ddd;
  border-radius: 4px;
  transition: background-color 0.3s;
}

.draggable-item:hover {
  background-color: #e6f7ff;
}

.droppable-cell {
  min-height: 50px;
  padding: 3px;
  text-align: center;
  background-color: #fafafa;
  border: 1px dashed #ccc;
  transition:
    background-color 0.3s,
    border-color 0.3s;
}

.droppable-cell.highlight {
  height: 100px;
  background-color: rgb(228 188 159);
  border-color: #e95f10;
  border-style: dashed;
  border-width: 3px;
}

.dropped-tag {
  margin: 5px 5px 0 0;
}
</style>
